package cn.javabb.core.shiro.realm;
import cn.hutool.core.util.StrUtil;
import cn.javabb.core.entity.sys.UserAuthDO;
import cn.javabb.core.model.StatusEnum;
import cn.javabb.core.service.biz.CatalogService;
import cn.javabb.core.service.sys.MenuService;
import cn.javabb.core.service.sys.RoleService;
import cn.javabb.core.service.sys.UserAuthService;
import cn.javabb.core.service.sys.UserService;
import cn.javabb.core.constant.Constant;
import cn.javabb.core.entity.biz.CatalogDO;
import cn.javabb.core.entity.sys.MenuDO;
import cn.javabb.core.entity.sys.RoleDO;
import cn.javabb.core.entity.sys.UserDO;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * shiro认证和授权
 * @author QINB
 * @CreateDate 2018年9月24日 下午2:56:53
 * @since V1.0
 */
public class UserRealm extends AuthorizingRealm {

    @Autowired
    @Lazy
    private UserService userService;
    @Autowired
    @Lazy
    private RoleService roleService;
    @Autowired
    @Lazy
    private MenuService menuService;
    @Autowired
    @Lazy
    private CatalogService catalogService;
    @Autowired
    private UserAuthService userAuthService;
    /**
     * 授权
     * Description: 
     *
     *
     * @author QINB 
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        UserDO user = (UserDO) SecurityUtils.getSubject().getPrincipal();
        //String currentLoginName = (String) principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();


        if (userService.isAdmin(user.getId())) {
            authorizationInfo.addRole(Constant.ADMIN_ROLE_CODE);
            authorizationInfo.addStringPermission("*:*");
            return authorizationInfo;
        }

        // 角色
        List<RoleDO> userRoles = roleService.listByUserId(user.getId());

        Set<String> roles = new HashSet<>();
        for (int i = 0; i < userRoles.size(); i++) {
            roles.add(userRoles.get(i).getRoleCode());
        }
        //给当前用户注入角色
        authorizationInfo.setRoles(roles);
        // 注入目录权限
        List<MenuDO> menuPermissionList = menuService.listMenuByUserId(user.getId());
        Set<String> permissions = new HashSet<>();
        for (int i = 0; i < menuPermissionList.size(); i++) {
            String authority = menuPermissionList.get(i).getPermissionCode();
            if (StringUtils.isNotBlank(authority)) {
                permissions.add(authority);
            }
        }
        // 注入前台板块权限
        List<CatalogDO> catalogPermissionList = catalogService.listCatalogPermissionsByUserId(user.getId());
        for (CatalogDO catalog : catalogPermissionList) {
            permissions.add("catalog:catalog_"+catalog.getCatalogId());
        }

        authorizationInfo.setStringPermissions(permissions);
        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String username = (String) authenticationToken.getPrincipal();
        UserDO user = userService.getByUserName(username);

        if (user == null) {
            throw new UnknownAccountException(); // 账号不存在
        }else if (user.getState() == StatusEnum.ABNORMAL.getCode()) {
            throw new LockedAccountException();  // 账号被锁定
        }
        // 根据用户名判断什么类型
        String authType = userAuthService.getAuthType(username);
        // 获取用户密码
        UserAuthDO userAuth = userAuthService.getUserAuth(user.getId(), authType);
        if (userAuth == null || StrUtil.isBlank(userAuth.getAuthPwd())) {
            throw new IncorrectCredentialsException(); // 密码错误
        }
        //将当前用户存入session
        SecurityUtils.getSubject().getSession().setAttribute(Constant.SESSION_USER, user);
        /* 传入密码自动判断是否正确
         * 参数1：传入对象给Principal
         * 参数2：正确的用户密码
         * 参数3：加盐处理
         * 参数4：固定写法，获取realm的Name
         */
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                user, userAuth.getAuthPwd(), ByteSource.Util.bytes(Constant.MD5_SALT), getName());
        return authenticationInfo;
    }
}
